/*
 * jngc, Java utility classes by Nicholas Coltharp
 * Copyright (C) 2010 Nicholas Coltharp <ngc1@rice.edu>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package edu.rice.ngc1.util.annotation.processor.tool;

import java.lang.annotation.Annotation;

import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Types;

/**
 * Utility class for operations on the compile-time object model.
 */
public final class Elements {

    /**
     * Private constructor to prevent construction.
     */
    private Elements() {}

    /**
     * Indicates whether a {@code TypeElement} represents an interface
     * or not.
     * 
     * @param e
     *            the element to inspect
     * @param types
     *            an object implementing the
     *            {@code javax.lang.model.util.Types} interface
     * @return {@code true} if {@code e} represents an interface;
     *         {@code false} otherwise
     */
    public static boolean isInterface(TypeElement e, Types types) {
        return (types.isSameType(e.getSuperclass(),
                types.getNoType(TypeKind.NONE)) && !e.getQualifiedName()
                .contentEquals("java.lang.Object"));
    }

    /**
     * Indicates whether an {@code Element} is annotated with the
     * given annotation.
     * 
     * @param e
     *            the element to inspect
     * @param a
     *            the annotation to check for on {@code e}
     * @return whether {@code e} is annotated with {@code a}
     */
    public static boolean isAnnotatedWith(Element e,
            Class<? extends Annotation> a) {
        return e.getAnnotation(a) != null;
    }

    /**
     * Indicates whether the given element represents an object
     * constructor.
     * 
     * @param e
     *            the {@code Element} to check
     * @return {@code true} if {@code e} represents a constructor;
     *         {@code false} otherwise
     */
    public static boolean isConstructor(Element e) {
        return ((e instanceof ExecutableElement) && isConstructor((ExecutableElement) e));
    }

    /**
     * Indicates whether the given {@code ExecutableElement}
     * represents an object constructor.
     * 
     * @param e
     *            the {@code Element} to check
     * @return {@code true} if {@code e} represents a constructor;
     *         {@code false} otherwise
     */
    public static boolean isConstructor(ExecutableElement e) {
        return e.getSimpleName().contentEquals("<init>");
    }

    /**
     * Indicates whether a given {@code TypeElement} has a concrete
     * superclass (i.e., it is not an interface or {@link Object}).
     * 
     * @param e
     *            the {@code TypeElement} to check
     * @param t
     *            an object implementing the
     *            {@code javax.lang.model.util.Types} interface
     * @return {@code true} if {@code e} has a concrete superclass;
     *         {@code false} otherwise
     */
    public static boolean hasConcreteSuperclass(TypeElement e, Types t) {
        TypeMirror sup = e.getSuperclass();
        return !t.isSameType(sup, t.getNoType(TypeKind.NONE));
    }
}
